// Copyright (c) 2005-2008, Simon Howard
// Permission to use, copy, modify, and/or distribute this software for any purpose
// with or without fee is hereby granted, provided that the above copyright notice
// and this permission notice appear in all copies.
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.

/// Test cases for comparison functions.

#[cfg(test)]
mod tests {
    use std::ptr;
    use std::cmp::Ordering;

    /// Compares two integers.
    fn int_compare(a: &i32, b: &i32) -> i32 {
        a.cmp(b) as i32
    }

    /// Checks if two integers are equal.
    fn int_equal(a: &i32, b: &i32) -> bool {
        a == b
    }

    /// Compares two pointers.
    fn pointer_compare<T>(a: *const T, b: *const T) -> i32 {
        a.cmp(&b) as i32
    }

    /// Checks if two pointers are equal.
    fn pointer_equal<T>(a: *const T, b: *const T) -> bool {
        a == b
    }

    /// Compares two strings lexicographically.
    fn string_compare(a: &str, b: &str) -> i32 {
        a.cmp(b) as i32
    }

    /// Checks if two strings are equal.
    fn string_equal(a: &str, b: &str) -> bool {
        a == b
    }

    /// Compares two strings lexicographically, ignoring case.
    fn string_nocase_compare(a: &str, b: &str) -> i32 {
        a.to_lowercase().cmp(&b.to_lowercase()) as i32
    }

    /// Checks if two strings are equal, ignoring case.
    fn string_nocase_equal(a: &str, b: &str) -> bool {
        a.to_lowercase() == b.to_lowercase()
    }

    #[test]
    fn test_int_compare() {
        let a = 4;
        let b = 8;
        let c = 4;

        // If first is less than second, result is negative.
        assert!(int_compare(&a, &b) < 0);

        // If first is more than second, result is positive.
        assert!(int_compare(&b, &a) > 0);

        // If both are equal, result is zero.
        assert_eq!(int_compare(&a, &c), 0);
    }

    #[test]
    fn test_int_equal() {
        let a = 4;
        let b = 8;
        let c = 4;

        // Returns true if both are equal.
        assert!(int_equal(&a, &c));

        // Returns false if not equal.
        assert!(!int_equal(&a, &b));
    }

    #[test]
    fn test_pointer_compare() {
        let array = [0; 5];

        // Negative if first argument is a lower memory address than the second.
        assert!(pointer_compare(&array[0], &array[4]) < 0);

        // Positive if the first argument is a higher memory address than the second.
        assert!(pointer_compare(&array[3], &array[2]) > 0);

        // Zero if the two arguments are equal.
        assert_eq!(pointer_compare(&array[4], &array[4]), 0);
    }

    #[test]
    fn test_pointer_equal() {
        let a = 0;
        let b = 0;

        // True if the two pointers are equal.
        assert!(pointer_equal(&a, &a));

        // False if the two pointers are not equal.
        assert!(!pointer_equal(&a, &b));
    }

    #[test]
    fn test_string_compare() {
        let test1 = "Apple";
        let test2 = "Orange";
        let test3 = "Apple";

        // Negative if first argument should be sorted before the second.
        assert!(string_compare(test1, test2) < 0);

        // Positive if the second argument should be sorted before the first.
        assert!(string_compare(test2, test1) > 0);

        // Zero if the two arguments are equal.
        assert_eq!(string_compare(test1, test3), 0);
    }

    #[test]
    fn test_string_equal() {
        let test1 = "this is a test string";
        let test2 = "this is a test string ";
        let test3 = "this is a test strin";
        let test4 = "this is a test strinG";
        let test5 = "this is a test string";

        // True if the two strings are equal.
        assert!(string_equal(test1, test5));

        // False if the two strings are different.
        assert!(!string_equal(test1, test2));
        assert!(!string_equal(test1, test3));

        // Case sensitive.
        assert!(!string_equal(test1, test4));
    }

    #[test]
    fn test_string_nocase_compare() {
        let test1 = "Apple";
        let test2 = "Orange";
        let test3 = "Apple";
        let test4 = "Alpha";
        let test5 = "bravo";
        let test6 = "Charlie";

        // Negative if first argument should be sorted before the second.
        assert!(string_nocase_compare(test1, test2) < 0);

        // Positive if the second argument should be sorted before the first.
        assert!(string_nocase_compare(test2, test1) > 0);

        // Zero if the two arguments are equal.
        assert_eq!(string_nocase_compare(test1, test3), 0);

        // Check ordering is independent of case.
        assert!(string_nocase_compare(test4, test5) < 0);
        assert!(string_nocase_compare(test5, test6) < 0);
    }

    #[test]
    fn test_string_nocase_equal() {
        let test1 = "this is a test string";
        let test2 = "this is a test string ";
        let test3 = "this is a test strin";
        let test4 = "this is a test strinG";
        let test5 = "this is a test string";

        // True if the two strings are equal.
        assert!(string_nocase_equal(test1, test5));

        // False if the two strings are different.
        assert!(!string_nocase_equal(test1, test2));
        assert!(!string_nocase_equal(test1, test3));

        // Case insensitive.
        assert!(string_nocase_equal(test1, test4));
    }
}
